package com.test.reader;

import com.test.BeanReference;
import com.test.definition.BeanDefinition;
import com.test.exception.XmlBeanDefinitionStoreException;
import com.test.handler.NamespaceHandler;
import com.test.registry.BeanDefinitionRegistry;

import com.test.resolver.DefaultNamespaceHandlerResolver;
import com.test.resolver.NamespaceHandlerResolver;
import com.test.value.PropertyValue;
import com.test.value.PropertyValues;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;

import java.util.List;

/**
 * 默认的Bean定义文档读取器，用于解析XML文档中的Bean定义
 */
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader{

    /**
     * XML标签和属性常量
     */
    private static final String BEAN_ELEMENT = "bean";
    private static final String PROP_ELEMENT = "property";
    private static final String ID_ATTRIBUTE = "id";
    private static final String NAME_ATTRIBUTE = "name";
    private static final String CLASS_ATTRIBUTE = "class";
    private static final String VALUE_ATTRIBUTE = "value";
    private static final String REF_ATTRIBUTE = "ref";
    private static final String INIT_METHOD_ATTRIBUTE = "init-method";
    private static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method";
    private static final String SCOPE_ATTRIBUTE = "scope";

    /**
     * 命名空间处理器解析器，用于解析自定义命名空间
     */
    private NamespaceHandlerResolver namespaceHandlerResolver;

    /**
     * 默认构造函数，使用默认的命名空间处理器解析器
     */
    public DefaultBeanDefinitionDocumentReader() {
        this.namespaceHandlerResolver = new DefaultNamespaceHandlerResolver();
    }

    /**
     * 带有自定义命名空间处理器解析器的构造函数
     * @param namespaceHandlerResolver 自定义的命名空间处理器解析器
     */
    public DefaultBeanDefinitionDocumentReader(NamespaceHandlerResolver namespaceHandlerResolver) {
        this.namespaceHandlerResolver = namespaceHandlerResolver;
    }

    /**
     * 设置命名空间处理器解析器
     * @param namespaceHandlerResolver 命名空间处理器解析器
     */
    public void setNamespaceHandlerResolver(NamespaceHandlerResolver namespaceHandlerResolver) {
        this.namespaceHandlerResolver = namespaceHandlerResolver;
    }

    /**
     * 注册Bean定义
     * @param doc XML文档
     * @param registry Bean定义注册表
     */
    public void registerBeanDefinitions(Document doc, BeanDefinitionRegistry registry) {
        Element root = doc.getRootElement();

        doRegisterBeanDefinitions(root, registry);
    }

    /**
     * 实际执行Bean定义的注册
     * @param root XML文档的根元素
     * @param registry Bean定义注册表
     */
    protected void doRegisterBeanDefinitions(Element root, BeanDefinitionRegistry registry) {
        List<Element> elements = root.elements();
        for (Element element : elements) {
            String namespaceUri = element.getNamespaceURI();

            if (namespaceUri != null && !namespaceUri.isEmpty()) {
                parseCustomElement(element, registry);
            } else if (element.getName().equals(BEAN_ELEMENT)){
                processBeanDefinition(element, registry);
            }
        }
    }

    /**
     * 解析自定义元素
     * @param ele 自定义元素
     * @param registry Bean定义注册表
     */
    protected void parseCustomElement(Element ele, BeanDefinitionRegistry registry) {
        String namespaceUri = ele.getNamespaceURI();
        NamespaceHandler handler = namespaceHandlerResolver.resolve(namespaceUri);

        if (handler == null) {
            throw new XmlBeanDefinitionStoreException("未找到命名空间 [" + namespaceUri + "] 的处理器");
        }
        handler.parse(ele, registry);
    }

    /**
     * 处理Bean定义
     * @param ele Bean定义元素
     * @param registry Bean定义注册表
     */
    protected void processBeanDefinition(Element ele, BeanDefinitionRegistry registry) {
        //解析bean元素的属性
        String id = ele.attributeValue(ID_ATTRIBUTE);
        String name = ele.attributeValue(NAME_ATTRIBUTE);
        String className = ele.attributeValue(CLASS_ATTRIBUTE);
        String initMethodName = ele.attributeValue(INIT_METHOD_ATTRIBUTE);
        String destroyMethodName = ele.attributeValue(DESTROY_METHOD_ATTRIBUTE);
        String scope = ele.attributeValue(SCOPE_ATTRIBUTE);

        //获取Class对象
        Class<?> clazz = null;
        try {
            clazz = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new XmlBeanDefinitionStoreException("找不到类 [" + className + "]", e);
        }

        //确定bean的名称
        String beanName = id != null && !id.isEmpty() ? id : name;
        if (beanName == null || beanName.isEmpty()) {
            beanName = Character.toLowerCase(clazz.getSimpleName().charAt(0)) + clazz.getSimpleName().substring(1);
        }

        //创建beanDefinition
        BeanDefinition beanDefinition = new BeanDefinition(clazz);

        //设置初始化和销毁方法
        if (initMethodName != null && !initMethodName.isEmpty()) {
            beanDefinition.setInitMethodName(initMethodName);
        }
        if (destroyMethodName != null && !destroyMethodName.isEmpty()) {
            beanDefinition.setDestroyMethodName(destroyMethodName);
        }

        // 设置作用域（如果存在）
        if (scope != null && !scope.isEmpty()) {
            beanDefinition.setScope(scope);
        }

        //解析property元素
        parsePropertyElements(ele, beanDefinition);
        //处理自定义属性
        parseCustomAttributes(ele, beanDefinition, registry);
        //注册beanDefinition
        registry.registerBeanDefinition(beanName, beanDefinition);
    }

    /**
     * 解析自定义属性并装饰Bean定义
     * 此方法负责处理元素中的自定义属性，根据属性的命名空间URI解析并应用相应的装饰逻辑
     *
     * @param ele 包含自定义属性的XML元素
     * @param beanDefinition 当前正在处理的Bean定义，用于存储解析后的属性信息
     * @param registry Bean定义注册表，用于注册或修改Bean定义
     */
    protected void parseCustomAttributes(Element ele, BeanDefinition beanDefinition, BeanDefinitionRegistry registry) {
        // 获取元素的所有属性
        List<Attribute> attributes = ele.attributes();
        // 遍历每个属性，以处理自定义属性
        for (Attribute attribute : attributes) {
            // 获取属性的命名空间URI
            String namespaceUri = attribute.getNamespaceURI();
            // 检查命名空间URI是否有效
            if (namespaceUri != null && !namespaceUri.isEmpty()){
                // 根据命名空间URI解析对应的命名空间处理器
                NamespaceHandler handler = namespaceHandlerResolver.resolve(namespaceUri);
                // 如果找到了对应的命名空间处理器，则调用其docorate方法进行装饰
                if (handler != null){
                    handler.docorate(ele, attribute.getName(), registry);
                }
            }
        }
    }


    /**
     * 解析属性元素
     * @param beanEle Bean定义元素
     * @param beanDefinition Bean定义对象
     */
    protected void parsePropertyElements(Element beanEle, BeanDefinition beanDefinition) {
        List<Element> propertyEles = beanEle.elements(PROP_ELEMENT);
        PropertyValues propertyValues = new PropertyValues();

        for (Element propertyEle : propertyEles) {
            parsePropertyElement( propertyEle, propertyValues);
        }
        beanDefinition.setPropertyValues(propertyValues);
    }

    /**
     * 解析单个属性元素
     * @param propertyEle 属性元素
     * @param propertyValues 属性值集合
     */
    protected void parsePropertyElement(Element propertyEle, PropertyValues propertyValues) {
        String propertyName = propertyEle.attributeValue(NAME_ATTRIBUTE);
        String propertyValue = propertyEle.attributeValue(VALUE_ATTRIBUTE);
        String propertyRef = propertyEle.attributeValue(REF_ATTRIBUTE);

        if (propertyName == null || propertyName.isEmpty()){
            throw new XmlBeanDefinitionStoreException("Bean的property元素必须指定name属性");
        }
        Object value;
        if (propertyValue != null && !propertyValue.isEmpty()){
            value = propertyValue;
        } else if (propertyRef != null && !propertyRef.isEmpty()){
            value = new BeanReference(propertyRef);
        } else {
            throw new XmlBeanDefinitionStoreException("Bean的property元素必须指定value或ref属性之一");
        }
        PropertyValue pv = new PropertyValue(propertyName, value);
        propertyValues.addPropertyValue(pv);
    }
}
